package com.quark.web.ui.logic;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.quark.data.type.QuarkPair;
import com.quark.data.type.QuarkVariable;
import com.quark.framework.database.QuarkDBExecuteManager;
import com.quark.framework.database.QuarkDBExecuterFactory;
import com.quark.framework.i18n.QuarkI18nManager;
import com.quark.framework.i18n.QuarkI18nTextProvider;
import com.quark.framework.ormapping.QuarkOrmBaseManager;
import com.quark.framework.ormapping.QuarkOrmEntity;
import com.quark.framework.ormapping.QuarkOrmProperty;
import com.quark.framework.utility.QuarkLog;
import com.quark.web.ui.base.QuarkUiSetting;
import com.quark.web.ui.base.QuarkUiTableElement;
import com.quark.web.ui.base.QuarkUiTrElement;
import com.quark.web.ui.field.QuarkUiFieldBase;
import com.quark.web.ui.field.QuarkUiNormalTextField;

public abstract class QuarkUiLogicBase {
	
	protected Class<? extends QuarkOrmEntity> hostClass = null;
	private List<String> propertyNames = new ArrayList<String>();
	private QuarkUiTableElement table = null;
	public static final int buildtypeCreateNew = 1;
	public static final int buildtypeEditExisting = 2;
	public static final int buildtypeItemList = 3;
	public static final int buildtypeCopy = 4;
	
	public QuarkUiLogicBase(Class<? extends QuarkOrmEntity> entityClass)
	{
		table = new QuarkUiTableElement("","",QuarkUiSetting.TABLE_EDITOR_CLASS,"");
		changeHostClass(entityClass);
	}
	
	public boolean changeHostClass(Class<? extends QuarkOrmEntity> newClass)
	{
		hostClass = newClass;
		Field[] fields = newClass.getFields();
		propertyNames.clear();
		for(Field i : fields)
		{
			if(i.getType().equals(QuarkOrmProperty.class))
			{
				propertyNames.add(i.getName());
			}
		}
		return true;
	}
	
	public static QuarkUiLogicBase createLogic(Class<? extends QuarkUiLogicBase> uiLogicClass, Class<? extends QuarkOrmEntity> relatedClass)
	{
		try {
			QuarkUiLogicBase instance = uiLogicClass.newInstance();
			return instance;
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
			e.printStackTrace();
		}
		return null;
	}
	
	public Class<?> getPropertyClass(String propertyName)
	{
		try {
			QuarkOrmEntity entity = hostClass.newInstance();
			if(entity.hasProperty(propertyName))
				return entity.getProperty(propertyName).getType();
			else
				return null;
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	private QuarkUiTrElement buildFrontHtml(int buildFlag, Object param)
	//should be things between <tr></tr>
	{
		return null;
	}
	
	private QuarkUiTrElement buildBackHtml(int buildFlag, Object param)
	//should be things between <tr></tr>
	{
		return null;
	}
	
	public String build(int buildFlag, Object param) 
	{
		QuarkI18nTextProvider i18n = QuarkI18nManager.getInstance().getI18nTextProvider(QuarkI18nManager.manager);
		QuarkUiTrElement trElement = new QuarkUiTrElement("", "", "", "");
		QuarkUiTrElement tr = buildFrontHtml(buildFlag, param);
		table.clearTr();
		if(tr != null)
			table.addTableRow(tr);
		boolean lineStart = true;
		//TODO FIX Organize
		for(int i = 0; i < propertyNames.size(); i ++)
		{
			String name = propertyNames.get(i);
			QuarkUiFieldBase field = buildProperty(buildFlag, param, name);
			if(field == null)
				continue;
			if(field.getColumnSpan() > 1)
			{
				if(!lineStart)
				{
					table.addTableRow(trElement);
					trElement = new QuarkUiTrElement("", "", "", "");
					trElement.addTd("", 2, 1);
					table.addTableRow(trElement);
				}
				trElement = new QuarkUiTrElement("", "", "", "");
				trElement.addTd(i18n.get(name), 4, 1, QuarkUiSetting.TD_NAME_CLASS);
				trElement.getLastTd().addAttribute("title", i18n.get(name + "_tip"));
				table.addTableRow(trElement);
				trElement = new QuarkUiTrElement("", "", "", "");
				trElement.addTd(field.createField(), 4, 1, QuarkUiSetting.TD_FIELD_CLASS);
				table.addTableRow(trElement);
				trElement = new QuarkUiTrElement("", "", "", "");
				lineStart = true;
				
			}
			else
			{
				trElement.addTd(i18n.get(name), 1, 1, QuarkUiSetting.TD_NAME_CLASS);
				trElement.getLastTd().addAttribute("title", i18n.get(name + "_tip"));
				trElement.addTd(field.createField(), 1, 1, QuarkUiSetting.TD_FIELD_CLASS);				
				if(!lineStart)
				{
					table.addTableRow(trElement);
					trElement = new QuarkUiTrElement("", "", "", "");
					lineStart = true;
				}
				else
				{
					lineStart = false;
				}
			}
		}
		if(!lineStart)
			table.addTableRow(trElement);
		tr = buildBackHtml(buildFlag, param);
		if(tr != null)
			table.addTableRow(tr);
		table.addAttribute("cellpadding", "0px");
		table.addAttribute("cellspacing", "5px");
		return table.createElement();
	}
	
	
	public QuarkUiFieldBase buildProperty(int buildFlag, Object param, String propertyName)
	{
		QuarkOrmEntity entity = (QuarkOrmEntity)param;
		QuarkUiNormalTextField field = new QuarkUiNormalTextField(entity.getClass().getSimpleName() + "." + propertyName);
		if(buildFlag == buildtypeCreateNew && !field.fillFieldWith(entity.getPropertyValue(propertyName)))
		{
			QuarkLog.logError(getClass().getName(), " fail create property field '" + propertyName + "'");
			return null;
		}
		return field;
	}
	public String onBuildListProperty(String property, QuarkOrmEntity pThis, QuarkVariable value)
	{
		return value.toString();
	}
	
	public List<List<QuarkUiListItemAttribute>> buildItemList(Integer page, Integer pageSize, Object param)
	{
		QuarkLog.log(new Exception("buildItemList not implemented!"));
		return null;
	}
	
	public List<List<QuarkUiListItemAttribute>> buildItemListHelper(List<? extends QuarkOrmEntity> entities, String[] propertyList)
	{
		Integer[] typeList = new Integer[propertyList.length];
		for(int i = 0; i < typeList.length; i ++)
		{
			typeList[i] = QuarkUiListItemAttribute.DISPLAY_TYPE_STRING;
		}
		return this.buildItemListHelper(entities, propertyList, typeList);
	}
	
	public List<List<QuarkUiListItemAttribute>> buildItemListHelper(List<? extends QuarkOrmEntity> entities, String[] propertyList, Integer[] typeList)
	{
		List<List<QuarkUiListItemAttribute>> list = new ArrayList<List<QuarkUiListItemAttribute>>();			
		for(int i = 0; i < entities.size(); i ++)
		{
			list.add(new ArrayList<QuarkUiListItemAttribute>());
			List<QuarkUiListItemAttribute> subList = list.get(list.size() - 1);
			for(Integer j = 0; j < propertyList.length; j ++)
			{
				if(typeList[j] == QuarkUiListItemAttribute.DISPLAY_TYPE_STRING)
				{
					subList.add(new QuarkUiListItemAttribute(propertyList[j], QuarkUiListItemAttribute.DISPLAY_TYPE_STRING, onBuildListProperty(propertyList[j], entities.get(i), new QuarkVariable(entities.get(i).getPropertyValue(propertyList[j]), entities.get(i).getProperty(propertyList[j]).getType()))));
				}
				else
				{
					QuarkLog.log(new Exception(getClass().getName() + (": unrecognized list item type " + typeList[j])));
				}
			}
		}
		return list;
	}
	
	public List<List<QuarkUiListItemAttribute>> buildItemListHelper(List<? extends QuarkOrmEntity> entities, String[] propertyList, Integer page, Integer pageSize)
	{
		Integer[] typeList = new Integer[propertyList.length];
		for(int i = 0; i < typeList.length; i ++)
		{
			typeList[i] = QuarkUiListItemAttribute.DISPLAY_TYPE_STRING;
		}
		return this.buildItemListHelper(entities, propertyList, typeList, page, pageSize);
	}
	
	public List<List<QuarkUiListItemAttribute>> buildItemListHelper(List<? extends QuarkOrmEntity> entities, String[] propertyList, Integer[] typeList, Integer page, Integer pageSize)
	{
		List<List<QuarkUiListItemAttribute>> list = new ArrayList<List<QuarkUiListItemAttribute>>();
		int startIndex = page * pageSize;
		int limit = ((page + 1) * pageSize < entities.size()) ? pageSize : (entities.size() - startIndex);
		Integer stringType = QuarkUiListItemAttribute.DISPLAY_TYPE_STRING;
		if(startIndex < entities.size())
		{			
			for(int i = startIndex; i < limit + startIndex; i ++)
			{
				list.add(new ArrayList<QuarkUiListItemAttribute>());
				List<QuarkUiListItemAttribute> subList = list.get(list.size() - 1);
				for(Integer j = 0; j < propertyList.length; j ++)
				{
					if(typeList[j] == QuarkUiListItemAttribute.DISPLAY_TYPE_STRING)
					{
						subList.add(new QuarkUiListItemAttribute(propertyList[j], QuarkUiListItemAttribute.DISPLAY_TYPE_STRING, onBuildListProperty(propertyList[j], entities.get(i), new QuarkVariable(entities.get(i).getPropertyValue(propertyList[j]), entities.get(i).getProperty(propertyList[j]).getType()))));
					}
					else
					{
						QuarkLog.log(new Exception(getClass().getName() + (": unrecognized list item type " + typeList[j])));
					}
				}
			}
		}
		return list;
	}
	
	public Class<? extends QuarkOrmEntity> getMainClass()
	{
		return hostClass;
	}
	
	public String getMainClassName()
	{
		return hostClass.getSimpleName();
	}
	
	
	public Integer getEntityTotalCount(String limit)
	{
		QuarkDBExecuteManager manager = QuarkDBExecuterFactory.getInstance().getExecuteManager(true);
		return manager.doGetCount(hostClass, limit);
	}
	
	public boolean processUiSubmitData(Map<String, String> result, String type, Object param)
	{		
		QuarkDBExecuteManager manager = QuarkDBExecuterFactory.getInstance().getExecuteManager(true);
		manager.beginTransaction();
		QuarkOrmEntity entity;
		try {
			entity = hostClass.newInstance();
			
			if(type.equals(QuarkUiManager.submitCreate))
			{
			
					int nCount = entity.fromMap(result);
					int nResult = -1;
					QuarkLog.logMessage(getClass().getName(), nCount + " fields processed");
					
					//add new data, do within transaction				
					nResult = manager.doInsert(entity);				
					return nResult != -1;			
			}
			else if(type.equals(QuarkUiManager.submitEdit))
			{
					int nCount = entity.fromMap(result);
					QuarkLog.logMessage(getClass().getName(), nCount + " fields processed");
					return manager.doUpdate(entity) != -1;
			}
			else if(type.equals(QuarkUiManager.submitDel))
			{
					return manager.doDelete(hostClass, entity.getUpdateKey().getName() + "=" + result.get("key")) != -1;
			}
			
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		manager.endTransaction();
		return false;
	}
	
	public List<String> getProperties()
	{
		return propertyNames;
	}
}
